external init : unit -> unit = "octi_rawb_init"

let _ = init()


module Bytes =
struct
  type t
  type info = [`Info_sizeof_int | `Info_sizeof_long | `Info_sizeof_intnat | `Info_Max_long | `Info_Min_long]
  external create :                   int -> t = "octi_rawb_bytes_create"
  external make_offset :         t -> int -> t = "octi_rawb_bytes_make_offset"
  external get_bbsize :            t -> int    = "octi_rawb_bytes_get_bbsize"
  external get_bbrefcount :        t -> int    = "octi_rawb_bytes_get_bbrefcount"
  external get_bbaddress :       t -> int      = "octi_rawb_bytes_get_bbaddress"
  external get_address :         t -> int      = "octi_rawb_bytes_get_address"
  external info       :       info -> int      = "octi_rawb_bytes_info"
  let get_offset b =
    (get_address b) - (get_bbaddress b)
  let get_size b =
    (get_bbsize b) - (get_offset b)
  module C =
  struct
    module Char =
    struct
      external set : t -> int -> char -> unit = "octi_rawb_bytes_c_char_set"
      external get : t -> int -> char         = "octi_rawb_bytes_c_char_get"
    end
    module Nativeint =
    struct
      external set : t -> int -> nativeint -> unit = "octi_rawb_bytes_c_nativeint_set"
      external get : t -> int -> nativeint         = "octi_rawb_bytes_c_nativeint_get"
    end
    module Float64 =
    struct
      external set : t -> int -> float -> unit = "octi_rawb_bytes_c_float64_set"
      external get : t -> int -> float         = "octi_rawb_bytes_c_float64_get"
    end
    module ComplexFloat64 =
    struct
      external set : t -> int -> Complex.t -> unit = "octi_rawb_bytes_c_complexfloat64_set"
      external get : t -> int -> Complex.t         = "octi_rawb_bytes_c_complexfloat64_get"
    end
    module Float32 =
    struct
      external set : t -> int -> float -> unit = "octi_rawb_bytes_c_float32_set"
      external get : t -> int -> float         = "octi_rawb_bytes_c_float32_get"
    end
    module ComplexFloat32 =
    struct
      external set : t -> int -> Complex.t -> unit = "octi_rawb_bytes_c_complexfloat32_set"
      external get : t -> int -> Complex.t         = "octi_rawb_bytes_c_complexfloat32_get"
    end
  end
end

module Vector =
struct
  exception Out_of_bounds
  exception Not_a_vector
  type kind = Vector | Subvector
  type t = {bytes:Bytes.t; word_size:int; first:int; last:int; kind:kind}
  let raw_create word_size first last =
    if last < first then raise Out_of_bounds;
    {bytes = Bytes.create (word_size*(1 - first + last));
     word_size = word_size; first = first; last = last; kind = Vector}
  let bytes v = v.bytes
  let word_size v = v.word_size
  let first_index v = v.first
  let last_index v = v.last
  let length v = 1 - v.first + v.last
  (*
    OLD :    0      ofirst                                      olast
    NEW : -offset   ofirst-offset   nfirst         nlast        olast-offset
    OLD                             nfirst+offset  nlast+offset
  *)
  let make_subvector v offset first last =
    if v.kind <> Vector then raise Not_a_vector;
    if last < first then raise Out_of_bounds;
    if first < v.first - offset then raise Out_of_bounds;
    if last > v.last - offset then raise Out_of_bounds;
    {bytes = Bytes.make_offset v.bytes (v.word_size * ( - v.first + offset + first));
     word_size = v.word_size; first = first; last = last; kind = Subvector}
  let c_index v i =
    if i < v.first || i > v.last then
      raise Out_of_bounds
    else
      (i - v.first)
  module Nativeint =
  struct
    let create first last = raw_create Nativeint.size first last
    let set v i x = Bytes.C.Nativeint.set v.bytes (c_index v i) x
    let mset v kvlist = List.iter (fun kv -> set v (fst kv) (snd kv)) kvlist
    let get v i = Bytes.C.Nativeint.get v.bytes (c_index v i)
    let fill_fun v f =
      for i = v.first to v.last do
	set v i (f i)
      done
    let fill_linstep v start step = (* arrondi à revoir ? *)
	fill_fun v (fun i -> Nativeint.add start (Nativeint.mul (Nativeint.of_int (i - v.first)) step))
    let make_linstep imin imax start step =
      let v = create imin imax
      in
	fill_linstep v start step;
	v
    let fold_left f x v =
      let r = ref x in
	for i = v.first to v.last do
	  r := f !r (get v i)
	done;
	!r
    let fold_right f v x =
      let r = ref x in
	for i = v.last downto v.first do
	  r := f (get v i) !r
	done;
	!r
    let to_list v =
      fold_right (fun x l -> x :: l) v []
  end
  module Float64 =
  struct
    let create first last = raw_create 8 first last
    let set v i x = Bytes.C.Float64.set v.bytes (c_index v i) x
    let mset v kvlist = List.iter (fun kv -> set v (fst kv) (snd kv)) kvlist
    let get v i = Bytes.C.Float64.get v.bytes (c_index v i)
    let fill_fun v f =
      for i = v.first to v.last do
	set v i (f i)
      done
    let fill_linspace v xmin xmax = (* arrondi à revoir ? *)
      let dx = (xmax -. xmin) /. (float_of_int (v.last - v.first))
      in
	fill_fun v (fun i -> xmin +. (float_of_int (i - v.first)) *. dx)
    let make_linspace imin imax xmin xmax =
      let v = create imin imax 
      in
	fill_linspace v xmin xmax;
	v
    let fold_left f x v =
      let r = ref x in
	for i = v.first to v.last do
	  r := f !r (get v i)
	done;
	!r
    let fold_right f v x =
      let r = ref x in
	for i = v.last downto v.first do
	  r := f (get v i) !r
	done;
	!r
    let to_list v =
      fold_right (fun x l -> x :: l) v []
  end
  module ComplexFloat64 =
  struct
    let create first last = raw_create 16 first last
    let set v i x = Bytes.C.ComplexFloat64.set v.bytes (c_index v i) x
    let mset v kvlist = List.iter (fun kv -> set v (fst kv) (snd kv)) kvlist
    let get v i = Bytes.C.ComplexFloat64.get v.bytes (c_index v i)
    let fill_fun v f =
      for i = v.first to v.last do
	set v i (f i)
      done
    let fold_left f x v =
      let r = ref x in
	for i = v.first to v.last do
	  r := f !r (get v i)
	done;
	!r
    let fold_right f v x =
      let r = ref x in
	for i = v.last downto v.first do
	  r := f (get v i) !r
	done;
	!r
    let to_list v =
      fold_right (fun x l -> x :: l) v []
  end
  module Float32 =
  struct
    let create first last = raw_create 4 first last
    let set v i x = Bytes.C.Float32.set v.bytes (c_index v i) x
    let mset v kvlist = List.iter (fun kv -> set v (fst kv) (snd kv)) kvlist
    let get v i = Bytes.C.Float32.get v.bytes (c_index v i)
    let fill_fun v f =
      for i = v.first to v.last do
	set v i (f i)
      done
    let fill_linspace v xmin xmax = (* arrondi à revoir ? *)
      let dx = (xmax -. xmin) /. (float_of_int (v.last - v.first))
      in
	fill_fun v (fun i -> xmin +. (float_of_int (i - v.first)) *. dx)
    let make_linspace imin imax xmin xmax =
      let v = create imin imax 
      in
	fill_linspace v xmin xmax;
	v
    let fold_left f x v =
      let r = ref x in
	for i = v.first to v.last do
	  r := f !r (get v i)
	done;
	!r
    let fold_right f v x =
      let r = ref x in
	for i = v.last downto v.first do
	  r := f (get v i) !r
	done;
	!r
    let to_list v =
      fold_right (fun x l -> x :: l) v []
  end
  module ComplexFloat32 =
  struct
    let create first last = raw_create 8 first last
    let set v i x = Bytes.C.ComplexFloat32.set v.bytes (c_index v i) x
    let mset v kvlist = List.iter (fun kv -> set v (fst kv) (snd kv)) kvlist
    let get v i = Bytes.C.ComplexFloat32.get v.bytes (c_index v i)
    let fill_fun v f =
      for i = v.first to v.last do
	set v i (f i)
      done
    let fold_left f x v =
      let r = ref x in
	for i = v.first to v.last do
	  r := f !r (get v i)
	done;
	!r
    let fold_right f v x =
      let r = ref x in
	for i = v.last downto v.first do
	  r := f (get v i) !r
	done;
	!r
    let to_list v =
      fold_right (fun x l -> x :: l) v []
  end
end

